package org.example.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import jakarta.annotation.Resource;
import org.example.lotterysystem.common.domain.dto.ShortMessageLoginDTO;
import org.example.lotterysystem.common.domain.dto.UserPasswordLoginDTO;
import org.example.lotterysystem.common.domain.dto.UserRegisterDTO;
import org.example.lotterysystem.common.domain.enums.UserIdentityEnum;
import org.example.lotterysystem.common.domain.vo.BaseUserInfoVO;
import org.example.lotterysystem.common.domain.vo.UserLoginVO;
import org.example.lotterysystem.common.domain.vo.UserRegisterVO;
import org.example.lotterysystem.common.errorcode.ErrorCodeConstants;
import org.example.lotterysystem.common.exception.ServiceException;
import org.example.lotterysystem.common.message.AliSmsService;
import org.example.lotterysystem.common.utils.CaptchaUtil;
import org.example.lotterysystem.common.utils.JWTUtil;
import org.example.lotterysystem.common.utils.RedisUtil;
import org.example.lotterysystem.common.utils.RegexUtil;
import org.example.lotterysystem.mapper.UserMapper;
import org.example.lotterysystem.mapper.dataobject.Encrypt;
import org.example.lotterysystem.mapper.dataobject.UserDO;
import org.example.lotterysystem.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class UserServiceImpl implements UserService {

    @Resource
    UserMapper userMapper;

    @Resource
    AliSmsService aliSmsService;

    @Resource
    RedisUtil redisUtil;

    @Value("${sms.code-expiration:300}")
    private Long phoneCodeExpiration;   //验证码存在时间，单位秒

    private final boolean fg=true;     //fg为true表示测试环境，不真正发送短信

    /**
     *注册
     */
    @Override
    public UserRegisterVO register(UserRegisterDTO userRegisterDTO) {
        //参数校验
        checkParam(userRegisterDTO);

        //构造
        UserDO userDO = new UserDO();
        userDO.setUserName(userRegisterDTO.getName());
        userDO.setEmail(userRegisterDTO.getMail());
        userDO.setPhoneNumber(new Encrypt(userRegisterDTO.getPhoneNumber()));
        userDO.setIdentity(userRegisterDTO.getIdentity());
        if (StringUtils.hasText(userRegisterDTO.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(userRegisterDTO.getPassword()));
        }

        //保存到数据库中
        userMapper.insert(userDO);

        //返回数据
        UserRegisterVO userRegisterVO=new UserRegisterVO();
        userRegisterVO.setUserId(userDO.getId());
        return userRegisterVO;
    }

    /**
     *发送验证码
     */
    @Override
    public boolean send(String phoneNumber) {
        if(!RegexUtil.checkMobile(phoneNumber)){
            //手机号不合法
            throw new ServiceException(ErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        String phoneCodeKey = getPhoneCodeKey(phoneNumber);

        //生成验证码，发送验证码
        String code= fg ? "123456" : CaptchaUtil.getCaptcha(6);

        //将验证码存入Redis中
        redisUtil.set(phoneCodeKey,code,phoneCodeExpiration);

        if(!fg){
            boolean sendMobileCode = aliSmsService.sendMobileCode(phoneNumber, code);
            if(!sendMobileCode){
                //验证码发送失败
                throw new ServiceException(ErrorCodeConstants.VERIFICATION_CODE_SEND_ERROR);
            }
        }

        return true;
    }

    /**
     * 使用密码登录
     */
    @Override
    public UserLoginVO userPasswordLogin(UserPasswordLoginDTO userPasswordLoginDTO) {
        //验证手机号是否正确
        if(!RegexUtil.checkMobile(userPasswordLoginDTO.getLoginName())){
            throw new ServiceException(ErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        //从数据库中获取用户信息
        UserDO userDO=userMapper.selectByPhone(new Encrypt(userPasswordLoginDTO.getLoginName()));

        //校验用户信息
        if(userDO==null){
            throw new ServiceException(ErrorCodeConstants.USER_INFO_IS_EMPTY);
        }
        if(StringUtils.hasText(userPasswordLoginDTO.getMandatoryIdentity()) &&
                !userPasswordLoginDTO.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ErrorCodeConstants.IDENTITY_ERROR);
        }
        if(!DigestUtil.sha256Hex(userPasswordLoginDTO.getPassword())
                .equals(userDO.getPassword())){
            throw new ServiceException(ErrorCodeConstants.PASSWORD_ERROR);
        }

        //生成JWT
        Map<String,Object> map=new HashMap<>();
        map.put("id",userDO.getId());
        map.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(map);

        UserLoginVO userLoginVO=new UserLoginVO();
        userLoginVO.setIdentity(userDO.getIdentity());
        userLoginVO.setToken(token);

        return userLoginVO;
    }

    /**
     * 使用验证码登录
     */
    @Override
    public UserLoginVO shortMessageLogin(ShortMessageLoginDTO shortMessageLoginDTO) {
        //验证手机号是否正确
        if(!RegexUtil.checkMobile(shortMessageLoginDTO.getLoginMobile())){
            throw new ServiceException(ErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        //从数据库中获取用户信息
        UserDO userDO=userMapper.selectByPhone(new Encrypt(shortMessageLoginDTO.getLoginMobile()));

        //校验用户信息
        if(userDO==null){
            throw new ServiceException(ErrorCodeConstants.USER_INFO_IS_EMPTY);
        }
        if(StringUtils.hasText(shortMessageLoginDTO.getMandatoryIdentity()) &&
                !shortMessageLoginDTO.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ErrorCodeConstants.IDENTITY_ERROR);
        }

        //获取key
        String phoneCodeKey = getPhoneCodeKey(shortMessageLoginDTO.getLoginMobile());
        //校验验证码
        String code = redisUtil.get(phoneCodeKey);
        if(!shortMessageLoginDTO.getVerificationCode().equals(code)){
            throw new ServiceException(ErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }

        //生成JWT
        Map<String,Object> map=new HashMap<>();
        map.put("id",userDO.getId());
        map.put("identity",userDO.getIdentity());
        String token = JWTUtil.genJwt(map);

        UserLoginVO userLoginVO=new UserLoginVO();
        userLoginVO.setIdentity(userDO.getIdentity());
        userLoginVO.setToken(token);

        return userLoginVO;
    }

    /**
     *根据身份查询用户列表，如果身份为空，获取所有人信息
     */
    @Override
    public List<BaseUserInfoVO> findBaseUserInfo(String identity) {
        List<BaseUserInfoVO> result=new ArrayList<>();
        List<UserDO> userDOList=null;
        if(identity==null){
            userDOList=userMapper.selectAll();
        }else{
            if(UserIdentityEnum.forName(identity)==null){
                throw new ServiceException(ErrorCodeConstants.IDENTITY_ERROR);   //身份不明
            }
            userDOList=userMapper.selectByIdentity(identity);
        }

        //将得到的数据存入result中
        for(UserDO userDo:userDOList){
            BaseUserInfoVO baseUserInfoVO=new BaseUserInfoVO();

            baseUserInfoVO.setUserId(userDo.getId());
            baseUserInfoVO.setUserName(userDo.getUserName());
            baseUserInfoVO.setIdentity(userDo.getIdentity());

            result.add(baseUserInfoVO);
        }

        return result;
    }


    private void checkParam(UserRegisterDTO userRegisterDTO){
        if(userRegisterDTO==null){
            throw new ServiceException(ErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        //1.检验身份
        if(UserIdentityEnum.forName(userRegisterDTO.getIdentity())==null){
            throw new ServiceException(ErrorCodeConstants.IDENTITY_ERROR);   //身份不明
        }
        //2.管理员密码不为空
        if(userRegisterDTO.getIdentity().equals(UserIdentityEnum.ADMIN.name()) && userRegisterDTO.getPassword()==null){
            throw new ServiceException(ErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        //3.校验邮箱格式
        if(!RegexUtil.checkMail(userRegisterDTO.getMail())){
            throw new ServiceException(ErrorCodeConstants.MAIL_ERROR);
        }
        //4.校验手机号格式
        if(!RegexUtil.checkMobile(userRegisterDTO.getPhoneNumber())){
            throw new ServiceException(ErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //5.校验密码格式
        if(userRegisterDTO.getIdentity().equals(UserIdentityEnum.ADMIN.name()) &&
                !RegexUtil.checkPassword(userRegisterDTO.getPassword())){
            throw new ServiceException(ErrorCodeConstants.PASSWORD_ERROR);
        }
        //6.校验邮箱是否被使用
        if(checkMailUsed(userRegisterDTO.getMail())){
            throw new ServiceException(ErrorCodeConstants.MAIL_USED);
        }
        //7.校验手机号是否被使用
        if(checkPhoneNumberUsed(userRegisterDTO.getPhoneNumber())){
            throw new ServiceException(ErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    private boolean checkMailUsed(String mail) {
        int count = userMapper.countByMail(mail);
        return count>0;
    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int count = userMapper.countByPhone(new Encrypt(phoneNumber));
        return count>0;
    }

    private String getPhoneCodeKey(String phone){
        return "PHONE_CODE_KEY:"+phone;
    }
}
